home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / basic / bwbasic.lha / bwbasic / bwb_cnd.c < prev    next >
C/C++ Source or Header  |  1992-11-12  |  27KB  |  1,074 lines

  1. /***************************************************************
  2.  
  3.         bwb_cnd.c       Conditional Expressions and Commands
  4.                         for Bywater BASIC Interpreter
  5.  
  6.                         Copyright (c) 1992, Ted A. Campbell
  7.  
  8.                         Bywater Software
  9.                         P. O. Box 4023
  10.                         Duke Station
  11.                         Durham, NC  27706
  12.  
  13.                         email: tcamp@acpub.duke.edu
  14.  
  15.         Copyright and Permissions Information:
  16.  
  17.         All U.S. and international copyrights are claimed by the
  18.         author. The author grants permission to use this code
  19.         and software based on it under the following conditions:
  20.         (a) in general, the code and software based upon it may be
  21.         used by individuals and by non-profit organizations; (b) it
  22.         may also be utilized by governmental agencies in any country,
  23.         with the exception of military agencies; (c) the code and/or
  24.         software based upon it may not be sold for a profit without
  25.         an explicit and specific permission from the author, except
  26.         that a minimal fee may be charged for media on which it is
  27.         copied, and for copying and handling; (d) the code must be
  28.         distributed in the form in which it has been released by the
  29.         author; and (e) the code and software based upon it may not
  30.         be used for illegal activities.
  31.  
  32. ***************************************************************/
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <math.h>
  37. #include <ctype.h>
  38. #include <string.h>
  39.  
  40. #include "bwbasic.h"
  41. #include "bwb_mes.h"
  42.  
  43. /* global variables visible to this file only */
  44.  
  45. static struct bwb_line * ws[ WHILELEVELS ];             /* WHILE stack */
  46. int ws_counter = 0;                                     /* WHILE stack counter */
  47.  
  48. int fs_counter = 0;                                     /* FOR stack counter */
  49.  
  50. /* declarations of functions visible to this file only */
  51.  
  52. static int cnd_thenels( char *buffer, int position, int *then, int *els );
  53. static int cnd_tostep( char *buffer, int position, int *to, int *step );
  54. static struct bwb_line *find_wend( struct bwb_line *l );
  55. static int var_setival( struct bwb_variable *v, int i );
  56. static int dec_fsc( int level );
  57.  
  58. /***    IF-THEN-ELSE ***/
  59.  
  60. /***************************************************************
  61.  
  62.         FUNCTION:       bwb_if()
  63.  
  64.         DESCRIPTION:    This function handles the BASIC IF
  65.                         statement.
  66.  
  67. ***************************************************************/
  68.  
  69. struct bwb_line *
  70. bwb_if( struct bwb_line *l )
  71.    {
  72.    register int i, n;
  73.    int then, els;
  74.    int pos;
  75.    struct exp_ese *e;
  76.    char tbuf[ MAXSTRINGSIZE + 1 ];
  77.    char then_buffer[ MAXSTRINGSIZE + 1 ];    /* hold THEN statement */
  78.    char elb_buffer[ MAXSTRINGSIZE + 1 ];     /* hold ELSE statement */
  79.  
  80.    #if INTENSIVE_DEBUG
  81.    sprintf( bwb_ebuf, "in bwb_if(): entry, line <%d> buffer <%s>",
  82.       l->number, &( l->buffer[ l->position ] ) );
  83.    bwb_debug( bwb_ebuf );
  84.    #endif
  85.  
  86.    /* Call bwb_exp() to evaluate the condition. This should return
  87.       with position set to the "THEN" statement */
  88.  
  89.    e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  90.  
  91.    #if INTENSIVE_DEBUG
  92.    sprintf( bwb_ebuf, "in bwb_if(): line <%d> condition returns <%d>",
  93.       l->number, exp_getival( e ) );
  94.    bwb_debug( bwb_ebuf );
  95.    #endif
  96.  
  97.    /* test for "THEN" and "ELSE" statements */
  98.  
  99.    cnd_thenels( l->buffer, l->position, &then, &els );
  100.  
  101.    #if INTENSIVE_DEBUG
  102.    sprintf( bwb_ebuf, "in bwb_if(): return from cnd_thenelse, line is <%s>", 
  103.       l->buffer );
  104.    bwb_debug( bwb_ebuf );
  105.    #endif
  106.  
  107.    if ( then != FALSE )
  108.       {
  109.       if ( els != FALSE )
  110.          {
  111.          then_buffer[ 0 ] = '\0';
  112.          n = 0;
  113.          for ( i = (then + 4); i < els; ++i )
  114.             {
  115.             then_buffer[ n ] = l->buffer[ i ];
  116.             ++n;
  117.             then_buffer[ n ] = '\0';
  118.             }
  119.          }
  120.       else
  121.          {
  122.          then_buffer[ 0 ] = '\0';
  123.          n = 0;
  124.          for ( i = (then + 4); l->buffer[ i ] != '\0'; ++i )
  125.             {
  126.             then_buffer[ n ] = l->buffer[ i ];
  127.             ++n;
  128.             then_buffer[ n ] = '\0';
  129.             }
  130.          }
  131.  
  132.       }
  133.  
  134.    /* test for THEN line-number */
  135.  
  136.    pos = 0;
  137.    adv_ws( then_buffer, &pos );
  138.    adv_element( then_buffer, &pos, tbuf );
  139.    if ( ( tbuf[ 0 ] >= '0' ) && ( tbuf[ 0 ] <= '9' ))
  140.       {
  141.       sprintf( tbuf, "GOSUB %s", then_buffer );
  142.       strcpy( then_buffer, tbuf );
  143.       }
  144.  
  145.    #if INTENSIVE_DEBUG
  146.    sprintf( bwb_ebuf, "in bwb_if(): THEN statement is <%s>", then_buffer );
  147.    bwb_debug( bwb_ebuf );
  148.    #endif
  149.  
  150.    #if INTENSIVE_DEBUG
  151.    sprintf( bwb_ebuf, "in bwb_if(): found THEN statement, line is <%s>", 
  152.       l->buffer );
  153.    bwb_debug( bwb_ebuf );
  154.    #endif
  155.  
  156.    if ( els != FALSE )
  157.       {
  158.       elb_buffer[ 0 ] = '\0';
  159.       n = 0;
  160.       for ( i = (els + 4); l->buffer[ i ] != '\0'; ++i )
  161.          {
  162.          elb_buffer[ n ] = l->buffer[ i ];
  163.          ++n;
  164.          elb_buffer[ n ] = '\0';
  165.          }
  166.  
  167.       #if INTENSIVE_DEBUG
  168.       sprintf( bwb_ebuf, "in bwb_if(): ELSE statement is <%s>", elb_buffer );
  169.       bwb_debug( bwb_ebuf );
  170.       #endif
  171.  
  172.       }
  173.  
  174.    #if INTENSIVE_DEBUG
  175.    sprintf( bwb_ebuf, "in bwb_if(): searched for ELSE statement, line is <%s>", 
  176.       l->buffer );
  177.    bwb_debug( bwb_ebuf );
  178.    #endif
  179.  
  180.    /* evaluate and execute */
  181.  
  182.    if ( exp_getival( e ) != FALSE )
  183.       {
  184.       if ( then == FALSE )
  185.          {
  186.          #if PROG_ERRORS
  187.          sprintf( bwb_ebuf, "IF without THEN" );
  188.          bwb_error( bwb_ebuf );
  189.          #else
  190.          bwb_error( err_syntax );
  191.          #endif
  192.          }
  193.       else
  194.          {
  195.      #if INTENSIVE_DEBUG
  196.      sprintf( bwb_ebuf, "in bwb_if(): executing then buffer <%s>",
  197.         then_buffer );
  198.      bwb_debug( bwb_ebuf );
  199.      #endif
  200.      return cnd_xpline( l, then_buffer );
  201.      }
  202.       }
  203.    else
  204.       {
  205.       if ( els != FALSE )
  206.          {
  207.      #if INTENSIVE_DEBUG
  208.      sprintf( bwb_ebuf, "in bwb_if(): executing else buffer <%s>",
  209.         elb_buffer );
  210.      bwb_debug( bwb_ebuf );
  211.      #endif
  212.      return cnd_xpline( l, elb_buffer );
  213.      }
  214.       }
  215.  
  216.    /* if neither then nor else were found */
  217.  
  218.    l->next->position = 0;
  219.    return l->next;
  220.  
  221.    }
  222.  
  223. /***************************************************************
  224.  
  225.         FUNCTION:       cnd_thenelse()
  226.  
  227.         DESCRIPTION:    This function searches through the
  228.                         <buffer> beginning at point <position>
  229.                         and attempts to find positions of THEN
  230.                         and ELSE statements.
  231.  
  232. ***************************************************************/
  233.  
  234. int
  235. cnd_thenels( char *buffer, int position, int *then, int *els )
  236.    {
  237.    int loop, t_pos, b_pos, p_word;
  238.    char tbuf[ MAXSTRINGSIZE + 1 ];
  239.  
  240.    #if INTENSIVE_DEBUG
  241.    sprintf( bwb_ebuf, "in cnd_thenelse(): entry, line is <%s>", buffer );
  242.    bwb_debug( bwb_ebuf );
  243.    #endif
  244.  
  245.    /* set then and els to FALSE initially */
  246.  
  247.    *then = *els = FALSE;
  248.  
  249.    /* loop to find words */
  250.  
  251.    p_word = b_pos = position;
  252.    t_pos = 0;
  253.    tbuf[ 0 ] = '\0';
  254.    loop = TRUE;
  255.    while( loop == TRUE )
  256.       {
  257.  
  258.       switch( buffer[ b_pos ] )
  259.          {
  260.          case '\0':                     /* end of string */
  261.             return TRUE;
  262.          case ' ':                      /* whitespace = end of word */
  263.          case '\t':
  264.  
  265.             #if INTENSIVE_DEBUG
  266.             sprintf( bwb_ebuf, "in cnd_thenels(): word is <%s>", tbuf );
  267.             bwb_debug( bwb_ebuf );
  268.             #endif
  269.  
  270.             if ( strncmp( tbuf, "THEN", (size_t) 4 ) == 0 )
  271.                {
  272.  
  273.                #if INTENSIVE_DEBUG
  274.                sprintf( bwb_ebuf, "in cnd_thenels(): THEN found at position <%d>.",
  275.                   p_word );
  276.                bwb_debug( bwb_ebuf );
  277.                sprintf( bwb_ebuf, "in cnd_thenelse(): after THEN, line is <%s>", buffer );
  278.                bwb_debug( bwb_ebuf );
  279.                #endif
  280.  
  281.                *then = p_word;
  282.                }
  283.             else if ( strncmp( tbuf, "ELSE", (size_t) 4 ) == 0 )
  284.                {
  285.  
  286.                #if INTENSIVE_DEBUG
  287.                sprintf( bwb_ebuf, "in cnd_thenels(): ELSE found at position <%d>.",
  288.                   p_word );
  289.                bwb_debug( bwb_ebuf );
  290.                sprintf( bwb_ebuf, "in cnd_thenelse(): after ELSE, line is <%s>", buffer );
  291.                bwb_debug( bwb_ebuf );
  292.                #endif
  293.  
  294.                *els = p_word;
  295.                }
  296.             ++b_pos;
  297.             p_word = b_pos;
  298.             t_pos = 0;
  299.             tbuf[ 0 ] = '\0';
  300.             break;
  301.  
  302.          default:
  303.             if ( islower( buffer[ b_pos ] ) != FALSE )
  304.                {
  305.                tbuf[ t_pos ] = toupper( buffer[ b_pos ] );
  306.                }
  307.             else
  308.                {
  309.                tbuf[ t_pos ] = buffer[ b_pos ];
  310.                }
  311.             ++b_pos;
  312.             ++t_pos;
  313.             tbuf[ t_pos ] = '\0';
  314.             break;
  315.          }
  316.  
  317.       }
  318.  
  319.    #if INTENSIVE_DEBUG
  320.    sprintf( bwb_ebuf, "in cnd_thenelse(): exit, line is <%s>", buffer );
  321.    bwb_debug( bwb_ebuf );
  322.    #endif
  323.  
  324.    return FALSE;
  325.  
  326.    }
  327.  
  328. /***************************************************************
  329.  
  330.         FUNCTION:       cnd_xpline()
  331.  
  332.         DESCRIPTION:    This function interprets a portion of a
  333.                         command line.
  334.  
  335. ***************************************************************/
  336.  
  337. struct bwb_line *
  338. cnd_xpline( struct bwb_line *l, char *buffer )
  339.    {
  340.    char l_buffer[ MAXSTRINGSIZE + 1 ];
  341.    struct bwb_line *nl;
  342.    struct bwb_line *rl;
  343.  
  344.    if ( ( nl = calloc( 1, sizeof( struct bwb_line ) ) ) == NULL )
  345.       {
  346.       bwb_error( err_getmem );
  347.       return l;
  348.       }
  349.  
  350.    strncpy( l_buffer, buffer, MAXSTRINGSIZE );
  351.  
  352.    nl->marked = FALSE;
  353.    nl->next = l->next;
  354.    nl->number = l->number;
  355.    nl->position = 0;
  356.    nl->buffer = l_buffer;
  357.  
  358.    #if INTENSIVE_DEBUG
  359.    sprintf( bwb_ebuf, "in cnd_xpline(): interpret line portion <%s>",
  360.       nl->buffer );
  361.    bwb_debug( bwb_ebuf );
  362.    #endif
  363.  
  364.    rl = bwb_xline( nl );
  365.  
  366.    if ( nl->cmdnum == getcmdnum( "GOTO" ) )
  367.       {
  368.       return rl;
  369.       }
  370.    
  371.    else if ( nl->cmdnum == getcmdnum( "GOSUB" ) )
  372.       {
  373.       return rl;
  374.       }
  375.    
  376.    else if ( nl->cmdnum == getcmdnum( "RETURN" ) )
  377.       {
  378.       #if INTENSIVE_DEBUG
  379.       sprintf( bwb_ebuf, "in cnd_xpline(): RETURN returning line <%d>",
  380.          rl->number );
  381.       bwb_debug( bwb_ebuf );
  382.       #endif
  383.  
  384.       l->cmdnum = getcmdnum( "RETURN" );
  385.       l->marked = FALSE;
  386.  
  387.       return rl;
  388.       }
  389.    
  390.    /* in all other cases, return the next line after the current one */
  391.  
  392.    l->next->position = 0;
  393.    return l->next;
  394.  
  395.    }
  396.  
  397. /***    WHILE-WEND ***/
  398.  
  399. /***************************************************************
  400.  
  401.         FUNCTION:       bwb_while()
  402.  
  403.         DESCRIPTION:    This function handles the BASIC WHILE
  404.                         statement.
  405.  
  406. ***************************************************************/
  407.  
  408. struct bwb_line *
  409. bwb_while( struct bwb_line *l )
  410.    {
  411.    register int n;
  412.    struct bwb_line *wendnext;
  413.    struct exp_ese *e;
  414.  
  415.    /* find the WEND statement */
  416.  
  417.    wendnext = find_wend( l );
  418.    if ( wendnext == NULL )
  419.       {
  420.       l->next->position = 0;                           /* error routine has already been called */
  421.       return l->next;                           /* error routine has already been called */
  422.       }
  423.  
  424.    /* call bwb_exp() to interpret the expression */
  425.  
  426.    e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  427.  
  428.    if ( exp_getival( e ) == TRUE )
  429.       {
  430.       ws[ ws_counter ] = l;
  431.       ++ws_counter;
  432.       l->next->position = 0;
  433.       return l->next;
  434.       }
  435.    else
  436.       {
  437.       wendnext->position = 0;
  438.       return wendnext;
  439.       }
  440.  
  441.    }
  442.  
  443. /***************************************************************
  444.  
  445.         FUNCTION:       bwb_wend()
  446.  
  447.         DESCRIPTION:    This function handles the BASIC WEND
  448.                         statement.
  449.  
  450. ***************************************************************/
  451.  
  452. struct bwb_line *
  453. bwb_wend( struct bwb_line *l )
  454.    {
  455.  
  456.    if ( ws_counter <= 0 )
  457.       {
  458.       #if PROG_ERRORS
  459.       sprintf( bwb_ebuf, "in bwb_wend(): WEND without WHILE" );
  460.       bwb_error( bwb_ebuf );
  461.       #else
  462.       bwb_error( err_syntax  );
  463.       #endif
  464.       l->next->position = 0;
  465.       return l->next;
  466.       }
  467.  
  468.    --ws_counter;
  469.    ws[ ws_counter ]->position = 0;
  470.    return ws[ ws_counter ];
  471.    }
  472.  
  473. /***************************************************************
  474.  
  475.         FUNCTION:       find_wend()
  476.  
  477.         DESCRIPTION:    This function searches for a line containing
  478.                         a WEND statement corresponding to a previous
  479.                         WHILE statement.
  480.  
  481. ***************************************************************/
  482.  
  483. struct bwb_line *
  484. find_wend( struct bwb_line *l )
  485.    {
  486.    struct bwb_line *current;
  487.    register int w_level;
  488.    int position;
  489.  
  490.    w_level = 1;
  491.    for ( current = l->next; current != &bwb_end; current = current->next )
  492.       {
  493.       position = 0;
  494.       line_start( current->buffer, &position, &( current->lnpos ),
  495.          &( current->lnum ),
  496.          &( current->cmdpos ),
  497.          &( current->cmdnum ),
  498.          &( current->startpos ) );
  499.       current->position = current->startpos;
  500.  
  501.       if ( current->cmdnum > -1 )
  502.          {
  503.  
  504.          if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_while )
  505.             {
  506.             ++w_level;
  507.  
  508.             #if INTENSIVE_DEBUG
  509.             sprintf( bwb_ebuf, "in bwb_wend(): found WHILE at line %d, level %d",
  510.                current->number, w_level );
  511.             bwb_debug( bwb_ebuf );
  512.             #endif
  513.  
  514.             }
  515.          else if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_wend )
  516.             {
  517.             --w_level;
  518.  
  519.             #if INTENSIVE_DEBUG
  520.             sprintf( bwb_ebuf, "in bwb_wend(): found WEND at line %d, level %d",
  521.                current->number, w_level );
  522.             bwb_debug( bwb_ebuf );
  523.             #endif
  524.  
  525.             if ( w_level == 0 )
  526.                {
  527.                return current->next;
  528.                }
  529.             }
  530.          }
  531.       }
  532.  
  533.    #if PROG_ERRORS
  534.    sprintf( bwb_ebuf, "WHILE without WEND" );
  535.    bwb_error( bwb_ebuf );
  536.    #else
  537.    bwb_error( err_syntax  );
  538.    #endif
  539.  
  540.    return NULL;
  541.  
  542.    }
  543.  
  544. /***    FOR-NEXT ***/
  545.  
  546. /***************************************************************
  547.  
  548.         FUNCTION:       bwb_for()
  549.  
  550.         DESCRIPTION:    This function handles the BASIC FOR
  551.                         statement.
  552.  
  553.     LIMITATION:    As implemented here, the NEXT statement
  554.             must be at the beginning of a program
  555.             line; a NEXT statement following a colon
  556.             will not be recognized and may cause the
  557.             program to hang up.
  558.  
  559. ***************************************************************/
  560.  
  561. struct bwb_line *
  562. bwb_for( struct bwb_line *l )
  563.    {
  564.    register int n;
  565.    int e, loop;
  566.    int to, step, p;
  567.    struct exp_ese *exp;
  568.    struct bwb_variable *v;
  569.    char tbuf[ MAXSTRINGSIZE + 1 ];
  570.  
  571.    /* get the variable name */
  572.  
  573.    exp_getvfname( &( l->buffer[ l->startpos ] ), tbuf );
  574.    v = var_find( tbuf );
  575.  
  576.    #if INTENSIVE_DEBUG
  577.    sprintf( bwb_ebuf, "in bwb_for(): variable name <%s>.", v->name );
  578.    bwb_debug( bwb_ebuf );
  579.    #endif
  580.  
  581.    /* increment the FOR stack counter and check it */
  582.  
  583.    ++fs_counter;                                /* increment the counter */
  584.    if ( fs_counter >= FORLEVELS )
  585.       {
  586.       #if PROG_ERRORS
  587.       sprintf( bwb_ebuf, "Maximum FOR levels exceeded." );
  588.       bwb_error( bwb_ebuf );
  589.       #else
  590.       bwb_error( err_overflow );
  591.       #endif
  592.       l->next->position = 0;
  593.       return l->next;
  594.       }
  595.  
  596.    /* initialize the FOR stack element for this level */
  597.  
  598.    fs[ fs_counter ].nextline = l;               /* set next line for loop */
  599.    fs[ fs_counter ].variable = v;            /* set variable */
  600.    fs[ fs_counter ].step = 1;                   /* set default step */
  601.    l->position += strlen( tbuf );           /* set current position to end of variable */
  602.  
  603.    /* at this point one should find an equals sign ('=') */
  604.  
  605.    loop = TRUE;
  606.    while( loop == TRUE )
  607.       {
  608.       switch( l->buffer[ l->position ] )
  609.          {
  610.          case '=':                              /* found equals sign; continue */
  611.             ++l->position;
  612.             loop = FALSE;
  613.             break;
  614.          case ' ':                              /* whitespace */
  615.          case '\t':
  616.             ++l->position;
  617.             break;
  618.          default:
  619.             #if PROG_ERRORS
  620.             sprintf( bwb_ebuf, "in bwb_for(): failed to find equals sign, buf <%s>",
  621.                &( l->buffer[ l->position ] ) );
  622.             bwb_error( bwb_ebuf );
  623.             #else
  624.             bwb_error( err_syntax );
  625.             #endif
  626.             l->next->position = 0;
  627.             return l->next;
  628.          }
  629.       }
  630.  
  631.    /* Find the TO and STEP statements */
  632.  
  633.    cnd_tostep( l->buffer, l->position, &to, &step );
  634.  
  635.    /* if there is no TO statement, then an error has ocurred */
  636.  
  637.    if ( to < 1 )
  638.       {
  639.       #if PROG_ERRORS
  640.       sprintf( bwb_ebuf, "FOR statement without TO" );
  641.       bwb_error( bwb_ebuf );
  642.       #else
  643.       bwb_error( err_syntax  );
  644.       #endif
  645.       l->next->position = 0;
  646.       return l->next;
  647.       }
  648.  
  649.    /* copy initial value to small buffer and evaluate it */
  650.  
  651.    tbuf[ 0 ] = '\0';
  652.    p = 0;
  653.    for ( n = l->position; n < to; ++n )
  654.       {
  655.       tbuf[ p ] = l->buffer[ n ];
  656.       ++p;
  657.       ++l->position;
  658.       tbuf[ p ] = '\0';
  659.       }
  660.  
  661.    #if INTENSIVE_DEBUG
  662.    sprintf( bwb_ebuf, "in bwb_for(): initial value string <%s>",
  663.       tbuf );
  664.    bwb_debug( bwb_ebuf );
  665.    #endif
  666.  
  667.    p = 0;
  668.    exp = bwb_exp( tbuf, FALSE, &p );
  669.    var_setival( fs[ fs_counter ].variable, exp_getival( exp ) );
  670.  
  671.    #if INTENSIVE_DEBUG
  672.    sprintf( bwb_ebuf, "in bwb_for(): initial value <%d> pos <%d>",
  673.       exp_getival( exp ), l->position );
  674.    bwb_debug( bwb_ebuf );
  675.    #endif
  676.  
  677.    /* copy target value to small buffer and evaluate it */
  678.  
  679.    tbuf[ 0 ] = '\0';
  680.    p = 0;
  681.    l->position = to + 2;
  682.    if ( step < 1 )
  683.       {
  684.       e = strlen( l->buffer );
  685.       }
  686.    else
  687.       {
  688.       e = step - 1;
  689.       }
  690.  
  691.    loop = TRUE;
  692.    n = l->position;
  693.    while( loop == TRUE )
  694.       {
  695.       tbuf[ p ] = l->buffer[ n ];
  696.       ++p;
  697.       ++l->position;
  698.       tbuf[ p ] = '\0';
  699.  
  700.       if ( n >= e )
  701.           {
  702.           loop = FALSE;
  703.           }
  704.  
  705.       ++n;
  706.  
  707.       if ( l->buffer[ n ] == ':' )
  708.          {
  709.          loop = FALSE;
  710.          }
  711.  
  712.       }
  713.  
  714.    #if INTENSIVE_DEBUG
  715.    sprintf( bwb_ebuf, "in bwb_for(): target value string <%s>",
  716.       tbuf );
  717.    bwb_debug( bwb_ebuf );
  718.    #endif
  719.  
  720.    p = 0;
  721.    exp = bwb_exp( tbuf, FALSE, &p );
  722.    fs[ fs_counter ].target = exp_getival( exp );
  723.  
  724.    #if INTENSIVE_DEBUG
  725.    sprintf( bwb_ebuf, "in bwb_for(): target value <%d> pos <%d>",
  726.       exp_getival( exp ), l->position );
  727.    bwb_debug( bwb_ebuf );
  728.    #endif
  729.  
  730.    /* If there is a STEP statement, copy it to the small buffer
  731.       and evaluate it */
  732.  
  733.    if ( step > 1 )
  734.       {
  735.       tbuf[ 0 ] = '\0';
  736.       p = 0;
  737.       l->position = step + 4;
  738.  
  739.       for ( n = l->position; n < strlen( l->buffer ); ++n )
  740.          {
  741.          tbuf[ p ] = l->buffer[ n ];
  742.          ++p;
  743.          ++l->position;
  744.          tbuf[ p ] = '\0';
  745.          }
  746.  
  747.       #if INTENSIVE_DEBUG
  748.       sprintf( bwb_ebuf, "in bwb_for(): step value string <%s>",
  749.          tbuf );
  750.       bwb_debug( bwb_ebuf );
  751.       #endif
  752.  
  753.       p = 0;
  754.       exp = bwb_exp( tbuf, FALSE, &p );
  755.       fs[ fs_counter ].step = exp_getival( exp );
  756.  
  757.       #if INTENSIVE_DEBUG
  758.       sprintf( bwb_ebuf, "in bwb_for(): step value <%d>",
  759.          exp_getival( exp ) );
  760.       bwb_debug( bwb_ebuf );
  761.       #endif
  762.  
  763.       }
  764.  
  765.    /* set position in current line for reset */
  766.  
  767.    fs[ fs_counter ].position = l->position;     /* position for reset */
  768.  
  769.    #if INTENSIVE_DEBUG
  770.    sprintf( bwb_ebuf, "in bwb_for(): ready to exit, position <%d>",
  771.       l->position );
  772.    bwb_debug( bwb_ebuf );
  773.    #endif
  774.  
  775.    /* proceed with processing */
  776.  
  777.    l->next->position = 0;
  778.    return l->next;
  779.  
  780.    }
  781.  
  782. /***************************************************************
  783.  
  784.         FUNCTION:       bwb_next()
  785.  
  786.         DESCRIPTION:    This function handles the BASIC NEXT
  787.                         statement.
  788.  
  789.     LIMITATION:    As implemented here, the NEXT statement
  790.             must be at the beginning of a program
  791.             line; a NEXT statement following a colon
  792.             will not be recognized and may cause the
  793.             program to hang up.
  794.  
  795. ***************************************************************/
  796.  
  797. struct bwb_line *
  798. bwb_next( struct bwb_line *l )
  799.    {
  800.    register int c;
  801.    int stack_level;
  802.    char tbuf[ MAXSTRINGSIZE + 1 ];
  803.  
  804.    /* Check the integrity of the FOR stack */
  805.  
  806.    if ( fs_counter <= 0 )
  807.       {
  808.       #if PROG_ERRORS
  809.       sprintf( bwb_ebuf, "NEXT without FOR" );
  810.       bwb_error( bwb_ebuf );
  811.       #else
  812.       bwb_error( err_nf );
  813.       #endif
  814.       l->next->position = 0;
  815.       return l->next;
  816.       }
  817.  
  818.    /* Check for argument */
  819.  
  820.    adv_ws( l->buffer, &( l->position ) );
  821.    switch( l->buffer[ l->position ] )
  822.       {
  823.       case '\0':
  824.       case '\n':
  825.       case '\r':
  826.       case ':':
  827.          #if PROG_ERRORS
  828.          sprintf( bwb_ebuf, "at line %d: NEXT: no variable specified.",
  829.             l->number );
  830.          bwb_error( bwb_ebuf );
  831.          #else
  832.          bwb_error( err_syntax );
  833.          #endif
  834.          l->next->position = 0;
  835.          return l->next;
  836.       default:
  837.          break;
  838.       }
  839.  
  840.    adv_element( l->buffer, &( l->position ), tbuf );
  841.  
  842.    stack_level = 0;
  843.    for ( c = 1; c <= fs_counter; ++c )
  844.       {
  845.       if ( strcmp( tbuf, fs[ c ].variable->name ) == 0 )
  846.          {
  847.          stack_level = c;
  848.          }
  849.       }
  850.    if ( stack_level == 0  )
  851.       {
  852.       #if PROG_ERRORS
  853.       sprintf( bwb_ebuf, "NEXT has invalid variable" );
  854.       bwb_error( bwb_ebuf );
  855.       #else
  856.       bwb_error( err_syntax );
  857.       #endif
  858.       l->next->position = 0;
  859.       return l->next;
  860.       }
  861.  
  862.    /* we now have a valid stack level; now increment the variable value */
  863.  
  864.    var_setival( fs[ stack_level ].variable,
  865.       var_getival( fs[ stack_level ].variable ) + fs[ stack_level ].step );
  866.  
  867.    #if INTENSIVE_DEBUG
  868.    sprintf( bwb_ebuf, "in bwb_next(): variable <%s> is <%d>",
  869.       fs[ stack_level ].variable->name,
  870.       var_getival( fs[ stack_level ].variable ) );
  871.    bwb_debug( bwb_ebuf );
  872.    #endif
  873.  
  874.    /* check for completion of the loop */
  875.  
  876.    if ( fs[ stack_level ].step > 0 )            /* if step is positive */
  877.       {
  878.       if ( var_getival( fs[ stack_level ].variable )
  879.          > fs[ stack_level ].target )
  880.          {
  881.  
  882.          /* decrement the FOR stack counter and return */
  883.  
  884.          dec_fsc( stack_level );
  885.          l->next->position = 0;
  886.          return l->next;
  887.          }
  888.       }
  889.    else                                         /* if step is negative */
  890.       {
  891.       if ( var_getival( fs[ stack_level ].variable )
  892.          < fs[ stack_level ].target )
  893.          {
  894.  
  895.          /* decrement the FOR stack counter and return */
  896.  
  897.          dec_fsc( stack_level );
  898.          l->next->position = 0;
  899.          return l->next;
  900.          }
  901.       }
  902.  
  903.    /* Target not reached: return to the top of the FOR loop */
  904.  
  905.    fs[ stack_level ].nextline->position = fs[ stack_level ].position;
  906.  
  907.    #if INTENSIVE_DEBUG
  908.    sprintf( bwb_ebuf, "in bwb_next(): return to line <%d> position <%d> char <%c>",
  909.       fs[ stack_level ].nextline->number,
  910.       fs[ stack_level ].nextline->position,
  911.       fs[ stack_level ].nextline->buffer[ fs[ stack_level ].nextline->position ] );
  912.    bwb_debug( bwb_ebuf );
  913.    #endif
  914.  
  915.    return fs[ stack_level ].nextline;
  916.  
  917.    }
  918.  
  919. /***************************************************************
  920.  
  921.         FUNCTION:       cnd_tostep()
  922.  
  923.         DESCRIPTION:    This function searches through the
  924.                         <buffer> beginning at point <position>
  925.                         and attempts to find positions of TO
  926.                         and STEP statements.
  927.  
  928. ***************************************************************/
  929.  
  930. int
  931. cnd_tostep( char *buffer, int position, int *to, int *step )
  932.    {
  933.    int loop, t_pos, b_pos, p_word;
  934.    char tbuf[ MAXSTRINGSIZE + 1 ];
  935.  
  936.    /* set then and els to FALSE initially */
  937.  
  938.    *to = *step = FALSE;
  939.  
  940.    /* loop to find words */
  941.  
  942.    p_word = b_pos = position;
  943.    t_pos = 0;
  944.    tbuf[ 0 ] = '\0';
  945.    loop = TRUE;
  946.    while ( loop == TRUE )
  947.       {
  948.  
  949.       switch( buffer[ b_pos ] )
  950.          {
  951.          case '\0':                     /* end of string */
  952.          case ':':            /* end of line segment */
  953.             return TRUE;
  954.          case ' ':                      /* whitespace = end of word */
  955.          case '\t':
  956.  
  957.             #if INTENSIVE_DEBUG
  958.             sprintf( bwb_ebuf, "in cnd_tostep(): word is <%s>", tbuf );
  959.             bwb_debug( bwb_ebuf );
  960.             #endif
  961.  
  962.             if ( strncmp( tbuf, "TO", (size_t) 2 ) == 0 )
  963.                {
  964.  
  965.                #if INTENSIVE_DEBUG
  966.                sprintf( bwb_ebuf, "in cnd_tostep(): TO found at position <%d>.",
  967.                   p_word );
  968.                bwb_debug( bwb_ebuf );
  969.                #endif
  970.  
  971.                *to = p_word;
  972.                }
  973.             else if ( strncmp( tbuf, "STEP", (size_t) 4 ) == 0 )
  974.                {
  975.  
  976.                #if INTENSIVE_DEBUG
  977.                sprintf( bwb_ebuf, "in cnd_tostep(): STEP found at position <%d>.",
  978.                   p_word );
  979.                bwb_debug( bwb_ebuf );
  980.                #endif
  981.  
  982.                *step = p_word;
  983.                }
  984.             ++b_pos;
  985.             p_word = b_pos;
  986.             t_pos = 0;
  987.             tbuf[ 0 ] = '\0';
  988.             break;
  989.  
  990.          default:
  991.             if ( islower( buffer[ b_pos ] ) != FALSE )
  992.                {
  993.                tbuf[ t_pos ] = toupper( buffer[ b_pos ] );
  994.                }
  995.             else
  996.                {
  997.                tbuf[ t_pos ] = buffer[ b_pos ];
  998.                }
  999.             ++b_pos;
  1000.             ++t_pos;
  1001.             tbuf[ t_pos ] = '\0';
  1002.             break;
  1003.          }
  1004.  
  1005.       }
  1006.  
  1007.    return TRUE;
  1008.  
  1009.    }
  1010.  
  1011. int
  1012. var_setival( struct bwb_variable *v, int i )
  1013.    {
  1014.  
  1015.    switch( v->type )
  1016.       {
  1017.       case INTEGER:
  1018.          * var_findival( v, v->array_pos ) = i;
  1019.          break;
  1020.       case DOUBLE:
  1021.          * var_finddval( v, v->array_pos ) = (double) i;
  1022.          break;
  1023.       case SINGLE:
  1024.          * var_findfval( v, v->array_pos ) = (float) i;
  1025.          break;
  1026.       default:
  1027.          #if INTENSIVE_DEBUG
  1028.          sprintf( bwb_ebuf, "in var_setival(): variable <%s> is not a number",
  1029.             v->name );
  1030.          bwb_error( bwb_ebuf );
  1031.          #else
  1032.          bwb_error( err_mismatch );
  1033.          #endif
  1034.       }
  1035.  
  1036.    /* successful assignment */
  1037.  
  1038.    return TRUE;
  1039.  
  1040.    }
  1041.  
  1042. int
  1043. dec_fsc( int level )
  1044.    {
  1045.    register int l;
  1046.  
  1047.    --fs_counter;
  1048.    if ( fs_counter < 0 )
  1049.       {
  1050.       fs_counter = 0;
  1051.       #if PROG_ERRORS
  1052.       sprintf( bwb_ebuf, "FOR stack counter decremented below 0." );
  1053.       bwb_error( bwb_ebuf );
  1054.       #else
  1055.       bwb_error( err_overflow );
  1056.       #endif
  1057.       return FALSE;
  1058.       }
  1059.  
  1060.    /* pull down the FOR stack if necessary */
  1061.  
  1062.    l = level;
  1063.    while( l <= fs_counter )
  1064.       {
  1065.       memcpy( &( fs[ l ] ), &( fs[ l + 1 ] ), sizeof( struct fse ) );
  1066.       }
  1067.  
  1068.    /* return */
  1069.  
  1070.    return TRUE;
  1071.  
  1072.    }
  1073.  
  1074.